package com.ruoyi.biz.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.ruoyi.biz.pojo.dto.ActiveValidDTO;
import com.ruoyi.biz.pojo.dto.GenCodeDTO;
import com.ruoyi.biz.pojo.vo.BizCodeStatVO;
import com.ruoyi.biz.pojo.vo.R;
import com.ruoyi.biz.util.CodeLevel;
import com.ruoyi.biz.util.CodeStatus;
import com.ruoyi.biz.util.GenCodeUtil;
import com.ruoyi.biz.util.RespCode;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.LogUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.biz.mapper.BizCodeMapper;
import com.ruoyi.biz.domain.BizCode;
import com.ruoyi.biz.service.IBizCodeService;
import com.ruoyi.common.core.text.Convert;
import org.springframework.transaction.annotation.Transactional;

/**
 * 激活码Service业务层处理
 *
 * @author jason
 * @date 2025-10-31
 */
@Service
public class BizCodeServiceImpl implements IBizCodeService {
    @Autowired
    private BizCodeMapper bizCodeMapper;

    /**
     * 查询激活码
     *
     * @param id 激活码主键
     * @return 激活码
     */
    @Override
    public BizCode selectBizCodeById(Long id) {
        return bizCodeMapper.selectBizCodeById(id);
    }

    /**
     * 查询激活码列表
     *
     * @param bizCode 激活码
     * @return 激活码
     */
    @Override
    public List<BizCode> selectBizCodeList(BizCode bizCode) {
        return bizCodeMapper.selectBizCodeList(bizCode);
    }

    /**
     * 新增激活码
     *
     * @param bizCode 激活码
     * @return 结果
     */
    @Override
    public int insertBizCode(BizCode bizCode) {
        bizCode.setCreateTime(DateUtils.getNowDate());
        return bizCodeMapper.insertBizCode(bizCode);
    }

    /**
     * 修改激活码
     *
     * @param bizCode 激活码
     * @return 结果
     */
    @Override
    public int updateBizCode(BizCode bizCode) {
        bizCode.setUpdateTime(DateUtils.getNowDate());
        return bizCodeMapper.updateBizCode(bizCode);
    }

    /**
     * 批量删除激活码
     *
     * @param ids 需要删除的激活码主键
     * @return 结果
     */
    @Override
    public int deleteBizCodeByIds(String ids) {
        return bizCodeMapper.deleteBizCodeByIds(Convert.toStrArray(ids));
    }

    /**
     * 删除激活码信息
     *
     * @param id 激活码主键
     * @return 结果
     */
    @Override
    public int deleteBizCodeById(Long id) {
        return bizCodeMapper.deleteBizCodeById(id);
    }

    /**
     * 激活
     *
     * @param param 请求参数
     * @return 激活结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R active(ActiveValidDTO param) {
        LogUtils.getAccessLog().info("【激活】开始 ===========> {}", param);
        // 1. 激活码是否合法
        List<BizCode> codes = getByCondition(param.getCode(), null, null, CodeStatus.DIS_ACTIVE.getStatus());
        if (CollUtil.isEmpty(codes)) {
            return R.fail(param, RespCode.CODE_INVALID);
        }
        // 一般来说激活码必须唯一
        BizCode bizCode = codes.get(0);
        if (StrUtil.isNotBlank(bizCode.getClientId())) {
            // 激活码存在已绑定的客户端id 一般来说不可能
            return R.fail(param, RespCode.INTERVAL_ERROR);
        }
        // 2. 客户端是否存在 (是否支持一个客户端多个码, 应该是要支持的) 覆盖掉之前绑定的
        // 3. 查看激活码有效期（不需要）

        // 4.直接绑定
        bizCode.setActiveTime(new Date());
        bizCode.setLastUnbindTime(new Date()); // 默认为激活时间
        bizCode.setStatus(CodeStatus.ACTIVE.getStatus());
        bizCode.setClientId(param.getClientId());
        if (Objects.isNull(bizCode.getType())) {
            // 默认永久
            bizCode.setType(0);
        }
        // 有效时长
        Integer day = CodeLevel.getExpire(bizCode.getType()).getDay();
        // 设置过期时间
        bizCode.setExpireTime(DateUtils.addDays(new Date(), day));
        // 更新
        updateBizCode(bizCode);
        LogUtils.getAccessLog().info("【激活】成功 ===========> , 激活码信息:{}", JSON.toJSONString(bizCode));
        // 激活成功, 返回激活码
        return R.success(bizCode.getCode());
    }

    /**
     * 校验状态
     *
     * @param param 请求参数
     * @return 激活结果
     */
    @Override
    public R checkStatus(ActiveValidDTO param) {
        List<BizCode> codes = getByCondition(param.getCode(), param.getClientId(), null, null);
        if (CollUtil.isEmpty(codes)) {
            return R.fail(param, RespCode.NOT_RECROD);
        }

        BizCode bizCode = codes.get(0);
        switch (bizCode.getStatus()) {
            case "0":
                // 未激活, 几乎不存在
                LogUtils.getErrorLog().error("【校验状态】失败, 未激活的激活码!");
                return R.fail(param, RespCode.INTERVAL_ERROR);
            case "1":
                break;
            case "2":
                // 已过期
                LogUtils.getErrorLog().error("【校验状态】失败, 已激活的激活码!");
                return R.fail(param, RespCode.EXIPRE);
        }

        return R.success(true);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<String> generate(GenCodeDTO param) {
        if (Objects.isNull(param.getType()) || Objects.isNull(param.getNum()) || Objects.isNull(param.getIsUp())) {
            return new ArrayList<>();
        }
        // LogUtils.getAccessLog().info("【批量生成激活码】参数:{}", param);

        List<String> nCodes = new ArrayList<>();
        for (int i = 0; i < param.getNum(); i++) {
            String code = GenCodeUtil.generateActivationCode();
            List<BizCode> codes = getByCondition(code, null, null, null);
            while (CollUtil.isNotEmpty(codes)) {
                code = GenCodeUtil.generateActivationCode();
                codes = getByCondition(code, null, null, null);
            }

            nCodes.add(code);

            BizCode bizCode = new BizCode();
            bizCode.setType(param.getType());
            bizCode.setCode(code);
            bizCode.setIsUp(param.getIsUp().toString());
            bizCode.setStatus(CodeStatus.DIS_ACTIVE.getStatus());
            bizCode.setCreateTime(new Date());
            bizCodeMapper.insertBizCode(bizCode);
        }

        return nCodes;
    }

    @Override
    public BizCodeStatVO statistic() {
        return bizCodeMapper.statistic();
    }

    private List<BizCode> getByCondition(String code, String clientId, String isUp, String status) {
        BizCode query = new BizCode();
        query.setCode(code);
        query.setClientId(clientId);
        query.setIsUp(isUp);
        query.setStatus(status);
        return bizCodeMapper.selectBizCodeList(query);
    }
}
